package com.jgp.workflow.service.impl;


import com.jgp.common.utils.JGPUtil;
import com.jgp.sys.ui.Pager;
import com.jgp.workflow.exception.WorkflowErrorCode;
import com.jgp.workflow.exception.WorkflowException;
import com.jgp.workflow.pojo.ViewProcessModel;
import com.jgp.workflow.service.EditorService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.persistence.entity.ModelEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2018/12/22
 */
@Slf4j
@Service
public class EditorServiceImpl implements EditorService {
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Override
    public Map queryModelEditor(String modelId) {
        Model model = repositoryService.getModel(modelId);
        Map<String, Object> result = null;
        if (Objects.nonNull(model)) {
            try {
                if (Objects.nonNull(model.getMetaInfo())) {
                    result = JGPUtil.jsonToMap(model.getMetaInfo());
                } else {
                    result = new HashMap<>();
                }
                
                String source = new String(repositoryService.getModelEditorSource(modelId), "UTF-8");
                result.put("modelId", modelId);
                Map<String, Object> metaInfoMap = JGPUtil.jsonToMap(source);
                Map<String, Object> properties = (Map<String, Object>) metaInfoMap.get("properties");
                String processKey = (String) properties.get("process_id");
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                                                                       .processDefinitionKey(processKey)
                                                                       .latestVersion().singleResult();
                properties.put(
                        "process_version",
                        Objects.isNull(processDefinition) ? 0 : processDefinition.getVersion()
                );
                metaInfoMap.put("properties", properties);
                result.put("model", metaInfoMap);
            } catch (IOException e) {
                return null;
            }
        }
        return result;
    }
    
    @Override
    public Model queryModelById(String modelId) {
       return repositoryService.getModel(modelId);
    }
    
    @Transactional
    @Override
    public void saveModelEditor(String modelId, String json_xml, String svg_xml, String modelName, String
            description) throws WorkflowException {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Model model = repositoryService.getModel(modelId);
            Map<String, Object> metaInfoMap = JGPUtil.jsonToMap(model.getMetaInfo());
            metaInfoMap.put("name", modelName);
            metaInfoMap.put("description", description);
            model.setMetaInfo(JGPUtil.toJson(metaInfoMap));
            model.setName(modelName);
            repositoryService.saveModel(model);
            
            repositoryService.addModelEditorSource(modelId, json_xml.getBytes("UTF-8"));
            TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(svg_xml.getBytes("UTF-8")));
            TranscoderOutput output = new TranscoderOutput(outputStream);
            
            PNGTranscoder transcoder = new PNGTranscoder();
            transcoder.transcode(input, output);
            byte[] result = outputStream.toByteArray();
            repositoryService.addModelEditorSourceExtra(modelId, result);
        } catch (IOException | TranscoderException e) {
            throw new WorkflowException(WorkflowErrorCode.SAVE_MODEL_EDITOR_FAIL, e);
        }
    }
    
    @Transactional
    @Override
    public void saveModel(String modelId, String modelName, String systemId, String category, String
            description) throws WorkflowException {
        ModelEntity model;
        Map<String, Object> metaInfoMap;
        try {
            if (Objects.isNull(modelId)) {
                model = (ModelEntity) repositoryService.newModel();
                metaInfoMap = new HashMap<>();
                metaInfoMap.put("description", description);
                metaInfoMap.put("name", modelName);
                Map<String, Object> stencilset = new HashMap<>();
                stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
                metaInfoMap.put("stencilset", stencilset);
                Integer version = 0;
                Map<String, Object> properties = new HashMap<>();
                properties.put("name", modelName);
                properties.put("documentation", description);
                properties.put("process_author", "");
                properties.put("process_namespace", category);
                properties.put("process_version", version);
                properties.put("process_id", "process_" + System.currentTimeMillis());
                metaInfoMap.put("properties", properties);
                model.setVersion(version);
            } else {
                model = (ModelEntity) repositoryService.getModel(modelId);
                metaInfoMap = JGPUtil.jsonToMap(model.getMetaInfo());
                metaInfoMap.put("description", description);
                metaInfoMap.put("name", modelName);
            }
            model.setMetaInfo(JGPUtil.toJson(metaInfoMap));
            model.setName(modelName);
            model.setTenantId(systemId);
            model.setCategory(category);
            repositoryService.saveModel(model);
            repositoryService.addModelEditorSource(model.getId(), model.getMetaInfo().getBytes("UTF-8"));
        } catch (IOException e) {
            throw new WorkflowException(WorkflowErrorCode.SAVE_MODEL_EDITOR_FAIL,e);
        }
    }
    
    @Override
    public List<ViewProcessModel> queryModels(Pager pager) throws WorkflowException {
        ModelQuery query = repositoryService.createModelQuery();
        Long count = query.count();
        List<Model> models = query.orderByCreateTime().desc()
                                  .listPage((pager.getCurrent() - 1) * pager.getPageSize(),
                                            pager.getPageSize()
                                  );
        pager.setTotalCount(count);
        float per = count % pager.getPageSize();
        pager.setTotalPageCount(per != 0 ? (count / pager.getPageSize() + 1) : count / pager.getPageSize());
    
        List<ViewProcessModel> processModels = new ArrayList<>();
        for (Model model : models) {
            ModelEntity me = (ModelEntity) model;
            ViewProcessModel processModel = new ViewProcessModel();
            processModel.setId(model.getId());
            processModel.setName(model.getName());
            Map<String,Object> metaInfo;
            metaInfo = JGPUtil.jsonToMap(model.getMetaInfo());
            if(Objects.isNull(metaInfo)){
                log.error("流程模型Meta信息转换失败！");
                return null;
            }
            processModel.setDescription((String)metaInfo.get("description"));
            processModel.setVersion(model.getVersion());
            processModel.setRevision(me.getRevision());
            processModel.setCreateTime(me.getCreateTime().getTime());
            processModel.setLastUpdateTime(me.getLastUpdateTime().getTime());
            processModel.setDeploymentId(me.getDeploymentId());
            
            if (Objects.nonNull(me.getDeploymentId())) {
                Deployment deployment = repositoryService.createDeploymentQuery()
                                                         .deploymentId(me.getDeploymentId()).singleResult();
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).latestVersion().singleResult();
                processModel.setKey(processDefinition.getKey());
                processModel.setDeploymentTime(deployment.getDeploymentTime().getTime());
            }
        
            processModels.add(processModel);
        }
        return processModels;
    }
    
    @Transactional
    @Override
    public void removeModel(String modelId) {
        Model model = queryModelById(modelId);
        if(Objects.nonNull(model.getDeploymentId())){
            repositoryService.deleteDeployment(model.getDeploymentId());
        }
        repositoryService.deleteModel(modelId);
    }
}
